package lesson5.example5;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;

import javassist.ClassPool;
import javassist.LoaderClassPath;
import net.bytebuddy.agent.ByteBuddyAgent;

// https://segmentfault.com/a/1190000040027690
public class ByteBuddyUtil {

    public final static Instrumentation instrumentation;
    public final static ClassPool classPool;

    static {
    	// Byte Buddy在项目运行时，可以通过以下方法获取到Instrumentation对象，无需配置Agent。
        instrumentation = ByteBuddyAgent.install();
		classPool = ClassPool.getDefault();
        // 指定路径，否则可能会出现javassist.NotFoundException的问题
        classPool.insertClassPath(new LoaderClassPath(Thread.currentThread().getContextClassLoader()));
    }

	public static void transformer(ClassFileTransformer cft, Class<?>... classes) {
		try {
			/**
			 * 注册一个Transformer，从此之后的类加载都会被 transformer 拦截。 ClassFileTransformer 的 transform
			 * 方法可以直接对类的字节码进行修改，但是只能修改方法体，不能变更方法签名、增加和删除方法/类的成员属性
			 */
			instrumentation.addTransformer(cft, true);
			int size = classes.length;
			Class<?>[] classArray = new Class<?>[size];
			System.arraycopy(classes, 0, classArray, 0, size);
			if (classArray.length > 0) {
				/**
			     * 对JVM已经加载的类重新触发类加载，使用上面调用addTransformer()注册的ClassFileTransformer
			     * 重新对类进行修饰
			     */
				instrumentation.retransformClasses(classArray);
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			instrumentation.removeTransformer(cft);
		}
	}
}
